{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Despacho múltiple / multiple dispatch"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "En este notebook vamos a explorar **multiple dispatch**, un concepto fundamental en Julia.\n",
    "\n",
    "Multiple dispatch permite software:\n",
    "- rápido\n",
    "- extendible\n",
    "- programable\n",
    "- divertido para experimentar"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Para entender el despacho múltiple en Julia, observemos el operador `+`. <br>\n",
    "\n",
    "Si llamamos `methods()` sobre `+`, podemos ver todas las definiciones de `+`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "methods(+)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Podemos usar el macro de `@which` para saber qué método en particular estamos usando de `+`.<br> \n",
    "\n",
    "Distintos métodos se usan en cada uno de estos ejemplos."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "@which 3 + 3"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "@which 3.0 + 3.0 "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "@which 3 + 3.0"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Aún más, pues podemos definir nuevos métodos de `+`. <br>\n",
    "\n",
    "Primero tenemos que importar `+` de Base."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "import Base: +"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Digamos que queremos concatenar elementos con  `+`. Sin extender el método, no funciona"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "\"hello \" + \"world!\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "@which \"hello \" + \"world!\""
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Entonces agregamos a `+` un método que toma dos cadenas y las concatena"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "+(x::String, y::String) = string(x, y)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "\"hello \" + \"world!\""
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "¡Funciona! Y si queremos más, podemos comprobarnos que Julia ha despachado sobre los tipos de \"hello\" y \"world!\", sobre el método que acabamos de definir"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "@which \"hello \" + \"world!\""
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": true
   },
   "source": [
    "Vamos por un ejemplo más"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "foo(x, y) = println(\"duck-typed foo!\")\n",
    "foo(x::Int, y::Float64) = println(\"foo con entero y flotante!\")\n",
    "foo(x::Float64, y::Float64) = println(\"foo con dos flotantes!\")\n",
    "foo(x::Int, y::Int) = println(\"foo con dos enteros!\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "foo(1, 1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "foo(1., 1.)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "foo(1, 1.0)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "foo(true, false)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Nota que el último ejemplo aplica por default el caso de 'duck-typed foo' porque no había un método definido exclusivamente para dos booleanos."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": true
   },
   "source": [
    "### Ejercicios\n",
    "\n",
    "#### 9.1\n",
    "\n",
    "Agrega un método para `+` que aplique un cifrado de César a una cadena (cómo en el notebook 6) tal que\n",
    "\n",
    "```julia\n",
    "\"hello\" + 4 == \"lipps\"\n",
    "```"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 9.2\n",
    "\n",
    "Checa que has extendido propiamente `+` recorriendo la próxima cadena para atrás por 3 letras:\n",
    "\n",
    "\"Gr#qrw#phggoh#lq#wkh#diidluv#ri#gudjrqv#iru#|rx#duh#fuxqfk|#dqg#wdvwh#jrrg#zlwk#nhwfkxs1\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "anaconda-cloud": {},
  "kernelspec": {
   "display_name": "Julia 0.6.1",
   "language": "julia",
   "name": "julia-0.6"
  },
  "language": "Julia",
  "language_info": {
   "file_extension": ".jl",
   "mimetype": "application/julia",
   "name": "julia",
   "version": "0.6.2"
  },
  "toc": {
   "nav_menu": {
    "height": "119px",
    "width": "251px"
   },
   "navigate_menu": true,
   "number_sections": true,
   "sideBar": true,
   "threshold": "2",
   "toc_cell": false,
   "toc_section_display": "block",
   "toc_window_display": false
  }
 },
 "nbformat": 4,
 "nbformat_minor": 1
}
